package com.yilin.tms.user.controller;

import com.google.gson.reflect.TypeToken;
import com.yilin.commons.encrypt.EncryptUtils;
import com.yilin.commons.encrypt.KeyPairMap;
import com.yilin.commons.encrypt.Md5Util;
import com.yilin.commons.exception.BusinessException;
import com.yilin.commons.util.JsonUtil;
import com.yilin.commons.util.StringUtil;
import com.yilin.tms.core.application.AppUtil;
import com.yilin.tms.core.application.PageData;
import com.yilin.tms.core.application.ReturnData;
import com.yilin.tms.core.commons.annotation.*;
import com.yilin.tms.core.commons.base.BaseController;
import com.yilin.tms.core.commons.model.AuthStatusData;
import com.yilin.tms.core.commons.utils.ParamUtil;
import com.yilin.tms.core.commons.utils.SMSUtil;
import com.yilin.tms.core.commons.utils.UserUtil;
import com.yilin.tms.core.components.redis.RedisClient;
import com.yilin.tms.core.components.redis.RedisKeys;
import com.yilin.tms.core.entity.user.RoleType;
import com.yilin.tms.core.entity.user.UserType;
import com.yilin.tms.core.entity.user.account.Authority;
import com.yilin.tms.core.entity.user.account.UserAccrual;
import com.yilin.tms.core.entity.user.hatch.HatchPlatProduct;
import com.yilin.tms.core.entity.user.organize.Organize;
import com.yilin.tms.core.entity.user.account.Account;
import com.yilin.tms.core.entity.user.organize.UserRole;
import com.yilin.tms.core.remote.IMessageRemote;
import com.yilin.tms.core.remote.IOrderRemote;
import com.yilin.tms.core.remote.IVehicleRemote;
import com.yilin.tms.user.service.*;
import com.yilin.tms.user.service.impl.AuthorityService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;

/**
 * 用户管理
 */
@RestController
@RequestMapping("/user/account/")
public class AccountController extends BaseController {

    @Resource
    private IGrantFunctionApiService grantFunctionApiService;
    @Resource
    private IAccountService accountService;
    @Resource
    private IOrganizeService organizeService;
    @Resource
    private IAuthService authService;
    @Resource
    private AuthorityService authorityService;
    @Resource
    private IHatchService hatchService;
    @Resource
    private IMessageRemote messageRemote;
    @Resource
    private IOrderRemote orderRemote;
    @Resource
    private IVehicleRemote vehicleRemote;

    /**
     * 根据ID获取用户信息
     */
    @PostMapping("getAccountById")
    @NotNull({"accountId"})
    @NoLoginSecurity
    public ReturnData<Account> getAccountById(@Explain("用户ID") String accountId) {
        Account account = accountService.getAccountById(accountId);
        if (account == null) return jsonView(false, "未查询到该用户");
        return jsonView(true, "获取成功", account);
    }

    /**
     * 根据用户KEY获取用户信息
     */
    @PostMapping("getAccountByApiKey")
    @NotNull({"apiKey"})
    public ReturnData<Account> getAccountByApiKey(@Explain("用户KEY") String apiKey) {
        Account account = accountService.getAccountByApiKey(apiKey);
        if (account == null) return jsonView(false, "未查询到该用户");
        return jsonView(true, "获取成功", account);
    }

    /**
     * 获取平台未生成或生产失败的数据
     */
    @NoLoginSecurity
    @PostMapping("getErrorTmsAccount")
    public ReturnData<List<Account>> getErrorTmsAccount() {
        List<Account> accountList = accountService.getErrorTmsAccount();
        return jsonView(true, "获取成功", accountList);
    }

    /**
     * 获取用户集合
     */
    @PostMapping("getAccountListByIds")
    @NotNull({"accountIds"})
    @NoLoginSecurity
    public ReturnData<List<Account>> getAccountListByIds(String[] accountIds) {
        List<Account> accountList = accountService.getAccountListByIds(accountIds);
        return jsonView(true, "获取成功", accountList);
    }

    /**
     * 检查用户名
     */
    @PostMapping("checkUsername")
    @NotNull({"username"})
    public ReturnData<Boolean> checkUsername(@Explain("账号") String username) {
        if (username.length() < 6 || username.length() > 18) {
            return jsonView(false, "仅能设置6-18位账号");
        }
        Account account = accountService.getAccountByUsername(username);
        if (account != null) return jsonView(false, "账号已存在");
        return jsonView(true, "检查成功");
    }

    /**
     * 获取系统顶级用户
     */
    @PostMapping("getSystemAdminUser")
    @SkipLoginVerify
    public ReturnData<Account> getSystemAdminUser() {
        Account account = accountService.getSystemAdminUser();
        if (account == null) return jsonErrView("系统顶级用户获取失败");
        account.setPassword(null);
        account.setSafePassword(null);
        account.setFingerprintSecretKey(null);
        return jsonView(true, "检查成功", account);
    }

    /**
     * 获取平易林顶级用户
     */
    @PostMapping("getSystemYilinUser")
    @SkipLoginVerify
    public ReturnData<Account> getSystemYilinUser() {
        Account account = accountService.getSystemYilinUser();
        if (account == null) return jsonErrView("系统易林用户获取失败");
        account.setPassword(null);
        account.setSafePassword(null);
        account.setFingerprintSecretKey(null);
        return jsonView(true, "获取成功", account);
    }

    /**
     * 获取用户所有下级账户信息
     * 根据平台ID获取下面所有用户
     */
    @PostMapping("getAccountChildPage")
    public ReturnData<PageData<Account>> getAccountChildPage(Account query, Integer page, Integer limit) {
        if (StringUtil.isEmpty(query.getId())) query.setOrganizeId(getLoginUser().getOrganizeId());
        if (StringUtil.isEmpty(query.getSort())) query.setSort("userType-ASC|roleType-ASC|organType-ASC");
        PageData<Account> map = accountService.getAccountChildPage(query, page, limit);
        return jsonView(SUCCESS_CODE, "获取成功", map);
    }

    /**
     * 开启指纹密码
     * 关闭时删除前端秘钥即可
     */
    @PostMapping("activationFingerprint")
    @NotNull({"passCode", "deviceId"})
    public ReturnData<Object> activationFingerprint(@Explain("密码CODE") String passCode, @Explain("设备号") String deviceId) {
        Boolean verifyPassCode = UserUtil.verifyPassCode(getLoginUser(), passCode);
        if (!verifyPassCode) return jsonView(false, "安全密码验证失败！");
        Account account = accountService.getAccountById(getLoginUser().getId());
        if (!deviceId.equals(account.getDeviceId())) return jsonView(FAIL_CODE, "设备验证失败");
        KeyPairMap keyPairMap = EncryptUtils.genKeyPairMap();
        if (keyPairMap == null) return jsonView(FAIL_CODE, "生成指纹秘钥失败");
        String token = Md5Util.md5(EncryptUtils.aesEncrypt(deviceId, null));
        String publicKey = EncryptUtils.aesEncrypt(keyPairMap.getPublicKey(), token);
        String privateKey = EncryptUtils.aesEncrypt(keyPairMap.getPrivateKey(), token);
        account.setFingerprintSecretKey(privateKey);
        accountService.saveOrUpdateAccount(account, getLoginUser());
        UserUtil.updateLoginUser(account);
        return jsonView(true, "变更密码成功！", publicKey);
    }

    /**
     * 验证安全密码
     * 验证时，密码和秘钥2选1即可
     */
    @PostMapping("verifySafePassword")
    @UserTarget
    public ReturnData<Object> verifySafePassword(@Explain("密码") String safePassword, @Explain("秘钥") String fingerprintKey) {
        if (StringUtil.isNotEmpty(safePassword)) accountService.verifySvePassword(getLoginUser(), safePassword);
        else accountService.verifySvePublicKey(getLoginUser(), fingerprintKey);
        // 验证密码升级：服务调用密码成功后，会返回一串识别码，识别码用于处理业务逻辑
        String passCode = UserUtil.generatePassCode(getLoginUser());
        return jsonView(true, "验证成功！", passCode);
    }

    /**
     * 设置安全密码
     */
    @PostMapping("updateSafePassword")
    @NotNull({"password", "verCode"})
    public ReturnData<Object> updateSafePassword(@Explain("新密码") String password, @Explain("验证码") String verCode) {
        if (!AppUtil.isNumeric(password) || password.length() != 6) {
            return jsonView(false, "安全密码必须是6位数纯数字！", null);
        }
        Account account = accountService.getAccountById(getLoginUser().getId());
        //检查手机验证码
        Map<String, Object> verifyCode = SMSUtil.verifyCode(account.getPhone(), verCode, SMSUtil.MsgType.updateSafePassword);
        if (!(Boolean) verifyCode.get(SMSUtil.SUCCESS)) {
            return jsonView(FAIL_CODE, (String) verifyCode.get(SMSUtil.MSG));
        }
        account.setSafePassword(AppUtil.md5(password));
        account.setSafeDisabled(false);
        account.setSafeFailCount(0);
        accountService.saveOrUpdateAccount(account, getLoginUser());
        UserUtil.updateLoginUser(account);
        return jsonView(true, "变更密码成功！");
    }

    /**
     * 变更密码
     */
    @PostMapping("updatePassword")
    @NotNull({"password", "verCode"})
    public ReturnData<Object> updatePassword(@Explain("密码") String password, @Explain("验证码") String verCode) {
        if (password.length() < 8) return jsonView(false, "密码设置不能低于8位！", null);
        Account account = accountService.getAccountById(getLoginUser().getId());
        //检查手机验证码
        Map<String, Object> verifyCode = SMSUtil.verifyCode(account.getPhone(), verCode, SMSUtil.MsgType.updatePassword);
        if (!(Boolean) verifyCode.get(SMSUtil.SUCCESS)) {
            return jsonView(FAIL_CODE, (String) verifyCode.get(SMSUtil.MSG));
        }
        account.setPassword(AppUtil.md5(password));
        accountService.saveOrUpdateAccount(account, getLoginUser());
        UserUtil.updateLoginUser(account);
        return jsonView(true, "变更密码成功！");
    }

    /**
     * 重置密码
     */
    @PostMapping("resettingPassword")
    public ReturnData<Object> resettingPassword(String accountId) {
        Account account = accountService.getAccountById(accountId);
        if (getLoginUser().getRoleType() != RoleType.manager) {
            return jsonErrView("您没有权限重置该用户密码");
        }
        if (!account.getOrganizeId().equals(getLoginUser().getOrganizeId())) {
            return jsonErrView("您没有权限重置该用户密码");
        }
        String newPassword = AppUtil.random(8);
        HatchPlatProduct platProduct = hatchService.getHatchPlatProductByPlatId(account.getSuperiorPlatId());
        String msg = "尊敬的用户（账号：%s）您好，您的管理员：%s 已为你重置账户密码，新的密码：%s，请尽快前往%s登录并完成密码修改！";
        String fmtMsg = String.format(msg, account.getUsername(), getLoginUser().getName(), newPassword, platProduct.getProductName());
        messageRemote.sendPhoneMessage(account.getPhone(), fmtMsg);
        account.setPassword(AppUtil.md5(newPassword));
        accountService.saveOrUpdateAccount(account, getLoginUser());
        UserUtil.updateLoginUser(account);
        return jsonView(true, "变更密码成功！");
    }

    /**
     * 获取当前登录用户信息
     */
    @PostMapping("getLoginUserInfo")
    public ReturnData<Account> getLoginUserInfo(String accountId) {
        if(StringUtil.isEmpty(accountId))accountId=getLoginUser().getId();
        Account userInfo = accountService.getAccountById(accountId);
        if (userInfo == null) return jsonView(NO_LOGIN, "您的登录已失效，请重新登录");
        //查询字段----组织
        Organize organize = organizeService.getOrganizeById(userInfo.getOrganizeId());
        userInfo.setOrganize(organize);
        userInfo.setOrganizeName(organize.getOrganizeName());
        userInfo.setOrganizeLogo(organize.getOrganizeLogo());
        //查询字段----认证
        List<AuthStatusData> authStatusDataList = authService.getUserAuthStatus(userInfo);
        userInfo.setAuthStatusList(authStatusDataList);
        List<Authority> authorityList=authorityService.getAuthorityListByyAccountId(accountId);
        userInfo.setAuthorityList(authorityList);
//        /// ### 更新授权列表
//        List<String> functionCodeList = grantFunctionApiService.getGrantFunctionApiCodeList(organize.getMemberTypeId());
//        UserUtil.saveGrantApiUrlList(userInfo.getToken(), functionCodeList);
//        /// ### 检查终端信息
//        accountService.checkGeoTerminal(userInfo);
        // ### 去除密码
        userInfo.setPassword(null);
        userInfo.setSafePassword(null);
        userInfo.setFingerprintSecretKey(null);
        userInfo.setSecretKey(null);
        UserUtil.updateLoginUser(userInfo);
        return jsonView(SUCCESS_CODE, true, "获取成功", userInfo);
    }

    /**
     * 修改用户信息
     */
    @PostMapping("updateAccount")
    public ReturnData<Object> updateAccount(Account param) {
        if (param.getId() == null) param.setId(getLoginUser().getId());
        if (param.getCredit() != null)
            throw new BusinessException("请不要用updateAccount方法更新用户信用信息！请切换到updateUserCredit接口");
        Account localAccount = accountService.getAccountById(param.getId());
        if (localAccount == null) return jsonView(false, "未查询到该用户");
        if (getLoginUser().getUserType() != UserType.shipperUser) {
            if (getLoginUser().getRoleType() == RoleType.manager && !getLoginUser().getOrganizeId().equals(localAccount.getOrganizeId())) {
                return jsonView(false, "只能修改您自己组织下的账户信息");
            } else if (getLoginUser().getRoleType() == RoleType.employee && !getLoginUser().getId().equals(localAccount.getId())) {
                return jsonView(false, "只能修改您自己的信息");
            }
        }
        accountService.updateAccount(getLoginUser(), param, localAccount);
        UserUtil.updateLoginUser(param);
        return jsonView(true, "修改成功");
    }

    /**
     * 修改用户信息
     */
    @PostMapping("updateAccountAndOrganize")
    public ReturnData<Object> updateAccount(String accountJson,String organizeJson) {
        Account account= JsonUtil.jsonToObject(accountJson,new TypeToken<Account>(){});
        Organize organize= JsonUtil.jsonToObject(organizeJson,new TypeToken<Organize>(){});
        ParamUtil.isNull(account.getId(),"获取用户失败");
        if(!Objects.equals(account.getId(), getLoginUser().getId())){
            return jsonView(false, "您没有权限修改");
        }
        accountService.updateAccountAndOrganize(getLoginUser(), account, organize);
        return jsonView(true, "修改成功");
    }

    /**
     * 修改用户省运管资料创建状态
     */
    @PostMapping("updateUserTmsDataState")
    @NotNull({"id"})
    @SkipLoginVerify
    public ReturnData<Object> updateUserTmsDataState(Account account) {
        Account localAccount = accountService.getAccountById(account.getId());
        if (localAccount == null) {
            return jsonView(false, "未查询到该用户");
        }
        if (account.getTmsDriverDataState() != null) {
            localAccount.setTmsDriverDataState(account.getTmsDriverDataState());
        }
        localAccount.setUpdateTime(new Date());
        accountService.updateById(localAccount);
        UserUtil.updateLoginUser(account);
        return jsonView(true, "修改成功");
    }

    /**
     * 绑定司机终端ID
     */
    @PostMapping("bindGeoTrackTerminalId")
    @NotNull({"accountId", "terminalId"})
    public ReturnData<Object> bindGeoTrackTerminalId(@Explain("司机ID") String accountId, @Explain("终端ID") String terminalId) {
        Account truckerAccount = accountService.getAccountById(accountId);
        truckerAccount.setGeoTerminalId(terminalId);
        accountService.saveOrUpdate(truckerAccount);
        UserUtil.updateLoginUser(truckerAccount);
        return jsonView(true, "终端绑定成功");
    }

    /**
     * 更新司机定位
     */
    @PostMapping("updateDevicePosition")
    @NotNull({"position"})
    @UserTarget(UserType.truckerUser)
    public ReturnData<Object> updateDevicePosition(@Explain("位置信息") String position) {
        Account truckerAccount = accountService.getAccountById(getLoginUser().getId());
        truckerAccount.setDevicePosition(position);
        accountService.saveOrUpdate(truckerAccount);
        UserUtil.updateLoginUser(truckerAccount);
        //司机绑定的车辆也要更新定位
        vehicleRemote.updateVehiclePosition(truckerAccount.getId(), position);
        return jsonView(true, "更新定位成功");
    }

    /**
     * 更改账户启用状态
     */
    @PostMapping(value = "updateUserStatus")
    @NotNull({"id", "userState"})
    public ReturnData<Object> updateUserStatus(Account account) {
        if (StringUtil.isEmpty(account.getId())) {
            return jsonView(false, "用户ID不能我空！");
        }
        Account local = accountService.getAccountById(account.getId());
        if (getLoginUser().getUserType().ordinal() >= local.getUserType().ordinal()) {
            return jsonView(false, "您没有权限操作该用户状态！");
        }
        local.setUserState(account.getUserState());
        accountService.saveOrUpdate(local);
        return jsonView(SUCCESS_CODE, "操作成功");
    }

    /**
     * 转让管理员
     */
    @PostMapping(value = "transferManager")
    @NotNull({"targetEmployeeId"})
    @SafeVerify
    public ReturnData<Object> transferManager(String targetEmployeeId) {
        if (getLoginUser().getRoleType() != RoleType.manager) {
            return jsonView(false, "仅管理员可操作此功能！");
        }
        if (targetEmployeeId.equals(getLoginUser().getId())) {
            return jsonView(false, "您已经是管理员！");
        }
        Account manager = accountService.getAccountById(getLoginUser().getId());
        Account account = accountService.getAccountById(targetEmployeeId);
        if (!account.getOrganizeId().equals(getLoginUser().getOrganizeId())) {
            return jsonView(false, "仅能转让给同组织的成员账户！");
        }
        Boolean exist = ParamUtil.isSuccess(orderRemote.checkExistRunOrderByAccountId(manager.getId()));
        if (exist) return jsonErrView("您还有订单未完成，为了不影响后续的订单进行，请先完成订单！");
        Boolean exist2 = ParamUtil.isSuccess(orderRemote.checkExistRunOrderByAccountId(account.getId()));
        if (exist2) return jsonErrView("该成员还有订单未完成，为了不影响后续的订单进行，请先等待其完成订单！");
        accountService.transferManager(manager, account);
        UserUtil.updateLoginUser(manager);
        UserUtil.updateLoginUser(account);
        return jsonView(SUCCESS_CODE, "操作成功");
    }

    /**
     * 用户注销/或管理员踢出账户
     */
    @PostMapping(value = "scrapAccount")
    @NotNull({"accountId"})
    public ReturnData<Object> scrapAccount(String accountId) {
        if (accountId != null && getLoginUser().getRoleType() != RoleType.manager) {
            return jsonView(false, "仅管理员可操作此功能！");
        }
        if (accountId == null) accountId = getLoginUser().getId();
        Account account = accountService.getAccountById(accountId);
        if (account.getRoleType() == RoleType.manager) {
            return jsonView(false, "管理员不可直接销户，请先解散组织！");
        }
        accountService.scrapAccount(getLoginUser(), account);
        return jsonView(SUCCESS_CODE, "操作成功");
    }

    /**
     * 停用/启用员工账户
     */
    @PostMapping(value = "enableOrDisableAccount")
    @NotNull({"accountId", "userState"})
    public ReturnData<Object> enableOrDisableAccount(String accountId, Account.UserState userState) {
        if (getLoginUser().getRoleType() != RoleType.manager) {
            return jsonView(false, "仅管理员可操作此功能！");
        }
        Account account = accountService.getAccountById(accountId);
        if (!getLoginUser().getOrganizeId().equals(account.getOrganizeId())) {
            return jsonView(false, "仅能操作自己的组织成员！");
        }
        if (account.getRoleType() == RoleType.manager) {
            return jsonView(false, "管理员不允许被停用！");
        }
        if (userState == null) {
            if (account.getUserState() == Account.UserState.disable) userState = Account.UserState.enable;
            if (account.getUserState() == Account.UserState.enable) userState = Account.UserState.disable;
        }
        account.setUserState(userState);
        accountService.updateById(account);
        UserUtil.updateLoginUser(account);
        return jsonView(SUCCESS_CODE, "操作成功");
    }

    /**
     * 更改账户信用信息
     */
    @PostMapping(value = "updateUserCredit")
    @NotNull({"accountId"})
    @UserTarget({UserType.adminUser, UserType.platformUser})
    public ReturnData<Object> updateUserCredit(String accountId, Double diffCredit, String reason) {
        if (diffCredit == null || diffCredit == 0) return jsonErrView("操作分数不可等于0");
        accountService.updateUserCredit(getLoginUser(), accountId, diffCredit, reason);
        return jsonView(SUCCESS_CODE, true, "操作成功", null);
    }

    /**
     * 更新用户累加信息
     */
    @PostMapping(value = "updateUserAccrual")
    @NotNull({"accountId"})
    public ReturnData<Object> updateUserAccrual(String accountId, UserAccrual userAccrual) {
        accountService.updateUserAccrual(getLoginUser(), accountId, userAccrual);
        return jsonView(SUCCESS_CODE, true, "操作成功", null);
    }

    /**
     * 更新API账户秘钥
     */
    @PostMapping("updateApiAccountKey")
    @NotNull({"accountId", "publicKey"})
    public ReturnData<Object> updateApiAccountKey(String accountId, String publicKey) {
//        Account account = accountService.getAccountById(accountId);
//        UserRole role = roleService.getUserRoleById(account.getOrganizeId(), account.getRoleId());
//        if (role.getRoleType() != RoleType.api) throw new BusinessException("秘钥仅限API类型用户");
//        account.setPublicKey(publicKey);
//        String secretKey = RedisClient.getInstance().hget(RedisKeys.ACCOUNT_API_PAIR_KEY, publicKey);
//        account.setSecretKey(secretKey);
//        accountService.saveOrUpdate(account);
//        UserUtil.updateLoginUser(account);
        return jsonView(true, "更新API账户秘钥成功");
    }

    /**
     * 修改员工角色
     */
    @PostMapping(value = "updateEmployeeRole")
    @NotNull({"accountId", "roleId"})
    public ReturnData<Object> updateEmployeeRole(String accountId, String roleId) {
//        Account account = accountService.getAccountById(accountId);
//        if (account == null) return jsonView(false, "未查询到该用户");
//        if (getLoginUser().getRoleType() != RoleType.manager) return jsonView(false, "仅管理员可操作此功能");
//        if (account.getRoleType()!=RoleType.employee) return jsonView(false, "仅可更改员工角色");
//        UserRole role = roleService.getUserRoleById(account.getOrganizeId(),roleId);
//        if (role==null) return jsonView(false, "未查询到目标角色");
//        if (role.getRoleType()!=RoleType.employee) return jsonView(false, "仅可更改为员工角色");
//        account.setRoleId(roleId);
//        account.setRoleName(role.getName());
//        accountService.updateById(account);
        return jsonView(true, "操作成功");
    }

    /**
     * 根据用户类型获取pushIds
     */
    @PostMapping(value = "getPushIdsByUserType")
    @NotNull({"userType"})
    @UserTarget({UserType.shipperUser, UserType.truckerUser})
    public ReturnData<String[]> getPushIdsByUserType(UserType userType) {
        String[] pushIds = accountService.getPushIdsByUserType(getLoginUser(), userType);
        return jsonView(true, "获取成功", pushIds);
    }

    /**
     * 修改头像
     */
    @PostMapping(value = "updateAvater")
    public ReturnData<Object> updateAvater(String urlImage) {
        Account account=accountService.getAccountById(getLoginUser().getId());
        account.setAvatar(urlImage);
        accountService.updateById(account);
        return jsonView(SUCCESS_CODE, true, "保存成功", null);
    }
    /**
     * 修改组织简介
     */
    @PostMapping(value = "updateOrganizeName")
    public ReturnData<Object> updateOrganizeName(String organizeName) {
        Organize organize=organizeService.getOrganizeById(getLoginUser().getOrganizeId());
        List<Account>  list=accountService.getAccountByOrganizeId(organize.getId());
        organize.setOrganizeName(organizeName);
        list.forEach(x->{
            x.setOrganizeName(organizeName);
        });
        return jsonView(SUCCESS_CODE, true, "保存成功", null);
    }


}
